package Logica;
import java.util.ArrayList;
import java.util.Random;

import Zombies.Basico;
import Zombies.Flotador;
import Zombies.Multiplicador;
import Zombies.Resucitador;
import Zombies.Soldado;
import Zombies.Zombie;

import Dinero.Billete;
import Dinero.Dinero;
import Dinero.Moneda;
import Graficas.Grafica;
import Graficas.Ventana;
import Humanos.Humano;
import Hilos.*;


public class Juego extends Thread{
	//ATRIBUTOS DE INSTANCIA
	protected int dinero;
	protected int puntaje;
	protected Tablero tablero;
	protected boolean sigueJuego;
	protected ArrayList<Zombie> zombiesEnJuego;
	protected Ventana ventana;//PARA PODER LLAMAR A LOS METODOS VICTORIA O DERROTA CUANDO EL JUEGO TERMINA, Y OTROS METODOS PARA ACTUALIZAR IMAGENES
	protected Grafica grafica;
	protected int zombiesMatados;//ALMACENA LA CANTIDAD DE ZOMBIES MATADOS EN CADA OLA
	protected int numeroOla;
	protected boolean juegoEnPausa;
	protected int totalOlas;//DEPENDE DE LA DIFICULTAD DEL JUEGO
	protected int zombiesOla;
	
	//CONSTRUCTOR
	public Juego(Ventana v,int numOla){
		ventana=v;grafica=new Grafica(ventana.getFondoJuego(),this);
		tablero=new Tablero(this);
		puntaje=0;dinero=100;
		sigueJuego=true;zombiesEnJuego=new ArrayList<Zombie>();
		numeroOla=0;juegoEnPausa=false;totalOlas=numOla;		
	}
	
	//COMANDOS
	public void incrementarDinero(int d){
		dinero+=d;
		ventana.actualizarDinero();//ACTUALIZA LA CANTIDAD DE DINERO EN LA GRAFICA
	}
	public void decrementarDinero(int d){
		dinero-=d;
		ventana.actualizarDinero();//ACTUALIZA LA CANTIDAD DE DINERO EN LA GRAFICA
	}
	public void setSigueJuego(boolean s){
		sigueJuego=s;
	}
	public void setPausa(boolean p){
		juegoEnPausa=p;
	}
	public void incrementarPuntaje(int p){
		puntaje+=p;
		ventana.actualizarPuntaje();//ACTUALIZA EL PUNTAJE EN LA GRAFICA
	}
	public void decrementarPuntaje(int p){
		if(puntaje-p>0)//EL PUNTAJE NO PUEDE SER NEGATIVO
			puntaje-=p;
		else puntaje=0;
		ventana.actualizarPuntaje();//ACTUALIZA EL PUNTAJE EN LA GRAFICA
	}
	
	public void colocarZombie(Zombie z){//COLOCA UN ZOMBIE EN EL JUEGO Y CREA SU HILO, ES LLAMADO SOLAMENTE POR ZOMBIE MULTIPLICADOR
		tablero.colocarZombie(z);
		(new HiloZombie(this,z,grafica)).start();
		zombiesOla++;
		
	}
	private void agregarZombie(){//SE AGREGA UN ZOMBIE EN EL TABLERO Y SE CREA SU HILO
		if(!zombiesEnJuego.isEmpty()){
			Zombie z=zombiesEnJuego.remove(0);//AGREGA EL PRIMER ZOMBIE DE LA OLA DE ZOMBIES
			tablero.colocarZombie(z);
			(new HiloZombie(this,z,grafica)).start();}
	}
	public void agregarHumano(Humano h){//AGREGA UN HUMANO EN EL TABLERO Y CREA SU HILO
		tablero.colocarHumano(h);
		new HiloHumano(h,this,grafica).start();
	}
	public void eliminarHumano(Humano h){//ES USADO CUANDO EL JUGADOR DESEA REMOVER UN HUMANO COLOCADO EN EL TABLERO
		h.setEstaVivo(false);
		incrementarDinero(h.getCosto()/2);
		h.morir();
	}
	private void insertarDinero(){//GENERA UN BILLETE Y LO COLOCA EN UNA POSICION AL AZAR, CREA SU HILO PARA HACERLO CAER POR LA PANTALLA
		Dinero d=generarDinero();
		if(d!=null){
			tablero.colocarDinero(d);
			(new HiloDinero(d,this,grafica)).start();}
	}
	
	public void agregarMoneda(int fila,int col){//AGREGA UNA MONEDA EN LA POSICION INDICADA, ES USADA SOLO POR HUMANO DALE CUANDO GENERA UNA MONEDA
		Dinero d=new Moneda(fila,col,this,grafica);
		tablero.colocarDinero(d);
		grafica.agregarDinero(d);
	}
	
	public void incrementarZombiesMatados(){//PARA SABER LA CANTIDAD DE ZOMBIES QUE SE VAN MATANDO 
		zombiesMatados++;
	}
	
	public void run(){
		zombiesMatados=0;
		int cont1=0;//SE USA PARA CONTAR CUANTO TIEMPO TRANSCURRIO DESDE QUE SE AGREGO UN ZOMBIE
		int cont2=0;//SE USA PARA CONTAR CUANTO TIEMPO TRANSCURRIO DESDE QUE SE AGREGO UN BILLETE
		zombiesOla=0;
		int tiempoAgregar=6;//INICIALMENTE SE AGREGA UN ZOMBIE CADA 6 SEGUNDOS
		try {
			Thread.sleep(8000);//EN ESTE TIEMPO SE MUESTRA LA IMAGEN DE CARGANDO JUEGO
		} catch (InterruptedException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();}
	
		while(sigueJuego){//MIENTRAS NO SE TERMINO EL JUEGO
			if(!juegoEnPausa){
				if(zombiesOla==zombiesMatados){//SE MATARON TODOS LOS ZOMBIES DE LA OLA, O RECIEN COMIENZA EL JUEGO
					if(numeroOla<totalOlas){//SI QUEDAN OLAS DE ATAQUE
						try {Thread.sleep(5000);}//TIEMPO PARA QUE EL JUGADOR PUEDE COLOCAR HUMANOS
						catch (InterruptedException e1) {
							e1.printStackTrace();}
						generarOlaZombies();//SE GENERA UNA OLA DE ZOMBIES
						grafica.mostrarNumeroOla(numeroOla,totalOlas);//CARTEL QUE INFORMA AL JUGADOR DE QUE SE VIENE UNA OLA
						if(numeroOla==0)//EN LA PRIMER OLA, APARECE UN BILLETE AL PRINCIPIO PARA QUE EL JUGADOR TENGA MAS DINERO
							insertarDinero();
						numeroOla++;
						zombiesOla=zombiesEnJuego.size();//CANTIDAD DE ZOMBIES EN LA OLA
						zombiesMatados=0;//ES UNA NUEVA OLA, NO SE MATO NINGUN ZOMBIE
						try {Thread.sleep(8000);}//TIEMPO EN APARECER LA OLA DE ZOMBIES
						catch (InterruptedException e) {
							e.printStackTrace();}
						tiempoAgregar--;}//A MEDIDA QUE SE AVANZA, LOS ZOMBIES SE AGREGAN MAS RAPIDO
					else{sigueJuego=false;//SE TERMINARON TODAS LAS OLAS DE ZOMBIES, VICTORIA DEL JUGADOR
						try {Thread.sleep(5000);}
						catch (InterruptedException e) {
							e.printStackTrace();}
						FinVictoriaJuego();}}//SE MUESTRA LA IMAGEN CORRESPONDIENTE
				else{if(cont1==tiempoAgregar){//SE DEBE AGREGAR UN ZOMBIE AL TABLERO
						agregarZombie();
						cont1=0;}
				 	 cont1++;
				 	if(cont2==15){//CADA 15 SEGUNDOS SE AGREGA UN BILLETE EN EL JUEGO
				 		insertarDinero();
				 		cont2=0;}
				 		cont2++;}}
			try {Thread.sleep(1000);}
			catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();}}
	}
	public void FinDerrotaJuego(){//SE PERDIO EL JUEGO
		ventana.derrota();
	}
	private void FinVictoriaJuego(){//SE GANO EL JUEGO
		puntaje+=puntajeUnidadesVivas();//SI QUEDARON UNIDADES VIVAS, SE INCREMENTA EL PUNTAJE DEL JUGADOR
		ventana.actualizarPuntaje();//ACTUALIZA EL VALOR DEL PUNTAJE		
		ventana.victoria();//SE MUESTRA LA IMAGEN CORRESPONDIENTE
		
	}
	
	private void generarOlaZombies(){
		Random r=new Random();int fila;
		if(0<=numeroOla){//LA PRIMER OLA TIENE 10 ZOMBIES
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Soldado(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Multiplicador(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Resucitador(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Flotador(fila,8,this));}			
		if(1<=numeroOla){//SI ES LA  SEGUNDA OLA SE AGREGAN 5 ZOMBIES MAS(15 EN TOTAL)
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Soldado(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Multiplicador(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Resucitador(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Flotador(fila,8,this));}
		if(2<=numeroOla){//SI ES LA TERCERA OLA SE AGREGAN 5 ZOMBIES MAS(20 EN TOTAL)
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Soldado(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Soldado(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Soldado(fila,8,this));}
		if(3<=numeroOla){//SI ES LA CUARTA OLA SE AGREGAN 5 ZOMBIES MAS(25 EN TOTAL)
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Multiplicador(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Soldado(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));
			fila=r.nextInt(5)+1;
			zombiesEnJuego.add(new Basico(fila,8,this));}
	}
		
	//CONSULTAS
	private Dinero generarDinero(){//GENERA UN BILLETE EN UNA POSICION AL AZAR DEL TABLERO
		Random r=new Random();
		Dinero d;
		int fila,col;int intentos=0;
		do{
			fila=r.nextInt(5)+1;
			col=r.nextInt(8);}
		while((sigueJuego)&&(tablero.hayDinero(fila, col))&&(intentos<20));//NO PUEDE HABER DOS BILLETES EN UNA MISMA POSICION, SE INTENTA INSERTAR HASTA 20		
		if(intentos<20)
			d=new Billete(fila,col,this,grafica);
		else d=null;
		return d;		
	}
	public boolean sigueJuego(){
		return sigueJuego;
	}
	public Tablero getTablero(){
		return tablero;
	}
	public int getDinero(){
		return dinero;
	}
	public int getPuntaje(){
		return puntaje;
	}
	public boolean juegoEnPausa(){
		return juegoEnPausa;
	}
	private int puntajeUnidadesVivas(){//POR CADA UNIDAD VIVA SE INCREMENTA EL PUNTAJE CORRESPONDIENTE
		int punt=0;
		for(Humano h:tablero.getHumanos())
			punt+=h.getPuntaje();
		return punt;
	}
	public boolean posicionOcupada(int f,int c){//PARA SABER SI YA HAY UN HUMANO EN ESA POSICION
		return tablero.hayHumanoFila(f,c);
	}
	public int totalOlas(){//PARA SABER EL NUMERO DE OLAS EN EL JUEGO(DEPENDE DE LA DIFICULTAD)
		return totalOlas;
	}
}
